#ifndef __STEP_MOTOR_USER_H__
#define __STEP_MOTOR_USER_H__

#include "motor_base.h"
#include "step_motor_driver.h"

#include <future>

enum StepMotorInfinityModeSwitch {
    STEP_MOTOR_INFINITY_MODE_OFF,
    STEP_MOTOR_INFINITY_MODE_ON
};

enum StepMotorHiResModeSwitch {
    STEP_MOTOR_HIRES_MODE_OFF,
    STEP_MOTOR_HIRES_MODE_ON
};

enum StepMotorResolutionLevel {
    STEP_MOTOR_MINISTEP_256,
    STEP_MOTOR_MINISTEP_128,
    STEP_MOTOR_MINISTEP_64,
    STEP_MOTOR_MINISTEP_32,
    STEP_MOTOR_MINISTEP_16,
    STEP_MOTOR_MINISTEP_8,
    STEP_MOTOR_MINISTEP_4,
    STEP_MOTOR_MINISTEP_2,
    STEP_MOTOR_MINISTEP_1
};

enum StepMotorSpeedRampingLevel {
    STEP_MOTOR_RAMP_PULSE_0 = 0,
    STEP_MOTOR_RAMP_PULSE_100 = 100,
    STEP_MOTOR_RAMP_PULSE_200 = 200,
    STEP_MOTOR_RAMP_PULSE_300 = 300,
    STEP_MOTOR_RAMP_PULSE_400 = 400,
    STEP_MOTOR_RAMP_PULSE_500 = 500,
    STEP_MOTOR_RAMP_PULSE_600 = 600,
    STEP_MOTOR_RAMP_PULSE_700 = 700,
    STEP_MOTOR_RAMP_PULSE_800 = 800,
    STEP_MOTOR_RAMP_PULSE_900 = 900,
    STEP_MOTOR_RAMP_PULSE_1000 = 1000
};

enum StepMotorReferencePosition {
    STEP_MOTOR_NOW_POSITION = -1,
    STEP_MOTOR_START_RESET_POSITION = -2
};

class StepMotorUser : public MotorBase {
private:
    int pulse_ = 0;                     // 脉冲数
    int frequency_ = 0;                 // 频率
    double resolution_ = 1.0;           // 细分
    int speed_ramping_ = 0;             // 加减速步数
    bool high_resolution_mode_ = 0;     // 超级细分（天文使用）

    const int min_frequency_;
    const int max_frequency_;
    const int hires_max_frequency_;
    const double step_angle_;
    const double reset_time_s_;
    const double backlash_;

    bool backlash_event_ = 0;

    double min_soft_limit_;
    double max_soft_limit_;

    int reset_dir_ = 0;

    std::future<int> future_;
    // StepMotorDriver driver;

public:
    StepMotorDriver driver;

public:
    StepMotorUser(int motor_id, double gear_ratio, int min_frequency, int max_frequency, int hires_max_frequency, double min_soft_limit, 
                  double max_soft_limit, double step_angle, double reset_time_s, double backlash)
    : MotorBase(motor_id, gear_ratio), min_frequency_(min_frequency), max_frequency_(max_frequency), hires_max_frequency_(hires_max_frequency), 
    min_soft_limit_(min_soft_limit), max_soft_limit_(max_soft_limit), step_angle_(step_angle), reset_time_s_(reset_time_s), backlash_(backlash), 
    driver(motor_id) {}

    StepMotorUser(const StepMotorUser&) = delete;             // 禁用拷贝构造
    StepMotorUser& operator=(const StepMotorUser&) = delete;  // 禁用拷贝赋值

    int setParameterInPositionInDegree(double end_position, double speed, int resolution_level, int speed_ramping, bool high_resolution_mode = STEP_MOTOR_HIRES_MODE_OFF);
    int setParameterInPositionInPulse(int end_position, int frequency, int resolution_level, int speed_ramping, bool high_resolution_mode =  STEP_MOTOR_HIRES_MODE_OFF);
    int setParameterInDegree(double angle, double speed, int resolution_level, int speed_ramping, bool direction, bool high_resolution_mode =  STEP_MOTOR_HIRES_MODE_OFF);
    int setParameterInDegree(double speed, int resolution_level, int speed_ramping, bool direction, bool high_resolution_mode =  STEP_MOTOR_HIRES_MODE_OFF);
    int setParameterInDegree(double angle, double speed, int resolution_level, double speed_ramping_time, bool direction, bool high_resolution_mode =  STEP_MOTOR_HIRES_MODE_OFF);
    int setParameterInDegree(double speed, int resolution_level, double speed_ramping_time, bool direction, bool high_resolution_mode =  STEP_MOTOR_HIRES_MODE_OFF);
    int setParameterInPulse(int pulse, int frequency, int resolution_level, int speed_ramping, bool direction, bool high_resolution_mode =  STEP_MOTOR_HIRES_MODE_OFF);
    int setParameterInPulse(int frequency, int resolution_level, int speed_ramping, bool direction, bool high_resolution_mode =  STEP_MOTOR_HIRES_MODE_OFF);
    int getEndPositionInPulse(int pulse, int resolution_level, int direction, int& end_position, int reference_position = STEP_MOTOR_NOW_POSITION);
    int getEndPositionInDegree(double angle, int resolution_level, int direction, double& end_position, double reference_position = STEP_MOTOR_NOW_POSITION);
    int checkPositionInPulse(int position, double resolution);
    int checkPositionInDegree(double angle);

    int run() override;
    int stop() override;
    int waitMotorToStop();
    int waitMotorToStop(double wait_time_s);
    int resetInPulse(int direction, int& start_position);
    int resetInDegree(int direction, double& start_position);
    int resetAndSetParameterInDegree(int reset_dir = 0, double angle_from_reference = 0, int direction_from_reference = 0, double reference_position = STEP_MOTOR_START_RESET_POSITION);
    int resetAndSetParameterInPulse(int reset_dir = 0, int pulse_from_reference = 0, int direction_from_reference = 0, int reference_position = STEP_MOTOR_START_RESET_POSITION);
    int resetAndRunInDegree(int reset_dir = 0, double angle_from_reference = 0, int direction_from_reference = 0, double reference_position = STEP_MOTOR_START_RESET_POSITION);
    int resetAndRunInPulse(int reset_dir = 0, int pulse_from_reference = 0, int direction_from_reference = 0, int reference_position = STEP_MOTOR_START_RESET_POSITION);
    int resetAndRunInPulseInParallel(int reset_dir = 0, int pulse_from_start = 0, int direction_from_start = 0, int reference_position = STEP_MOTOR_START_RESET_POSITION);
    int resetAndRunInDegreeInParallel(int reset_dir = 0, double angle_from_reference = 0, int direction_from_start = 0, double reference_position = STEP_MOTOR_START_RESET_POSITION);
    int parallelReturn();
    int changeSpeed(double speed, bool print_log = false);
    int changeFrequency(int frequency);
    int changeDirection(bool direction, bool print_log = false);

    bool getMotionState();
    bool getLimitState();
    bool getLimitState(int direciton);
    int getAbsolutePositionInPulse(int resolution_level, int& absolute_position);
    int getAbsolutePositionInDegree(int resolution_level, double& absolute_position_angle);
    int getRelativePosition(int& relative_position);
    double getRunTime() const { return run_time_; }
    bool getDirection() const { return direction_; }

private:
    int runBacklash();

    int resolutionLevel2Resolution(int resolution_level, double& resolution);
    int angle2Pulse(double angle, double resolution, int& pulse);
    int pulse2Angle(int pulse, double resolution, double& angle);
    int speed2Frequency(double speed, double resolution, bool high_resolution_mode, int& frequency);
    int frequency2Speed(int& frequency, double resolution, bool high_resolution_mode, double& speed);
    int checkSpeedRamping(int frequency, int& speed_ramping);
    int checkFrequency(int& frequency, double resolution, bool high_resolution_mode);
    int checkPulse(int pulse);
    int checkAngle(double angle);
    int checkResolutionLevel(int resolution_level);
    void calculateRunTime();

    int waitMotorToRun(double wait_time_s);
    int waitMotorToLimit(double wait_time_s);
    int waitMotorToReset(int& reset_position);

    void printAllParameter() const;
};


#endif